package com.steakliu.sun.serializer;

import com.steakliu.sun.serializer.api.SunSerializer;
import com.steakliu.sun.spi.annotation.Join;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import org.springframework.objenesis.Objenesis;
import org.springframework.objenesis.ObjenesisStd;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 功能说明：
 * <p>
 * Original @Author: steakliu-刘牌, 2023-02-16  09:35
 * <p>
 * Copyright (C)2020-2022  steakliu All rights reserved.
 */
@Join
public class ProtostuffSerializer implements SunSerializer {

    private final Map<Class<?>, Schema<?>> map = new ConcurrentHashMap<>();

    private static final Objenesis objenesis = new ObjenesisStd();

    private static final LinkedBuffer linkedBuffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);

    private <T> Schema<T> getSchema(Class<T> clazz) {
        Schema<T> schema = (Schema<T>) map.get(clazz);
        if (null == schema) {
            schema = RuntimeSchema.createFrom(clazz);
            map.put(clazz, schema);
        }
        return schema;
    }

    @Override
    public <T> byte[] serialize(T obj) {
        try {
            Schema<T> schema = (Schema<T>) getSchema(obj.getClass());
            return ProtostuffIOUtil.toByteArray(obj, schema, linkedBuffer);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T> T deserialize(byte[] bytes, Class<T> clazz) {
        try {
            T t = objenesis.newInstance(clazz);
            Schema<T> schema = getSchema(clazz);
            ProtostuffIOUtil.mergeFrom(bytes, t, schema);
            return t;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
